package com.sbtr.controller;

import cn.hutool.core.net.URLEncodeUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sbtr.business.classify.entity.AlgoCorpgenerate;
import com.sbtr.business.classify.service.AlgoCorpgenerateService;
import com.sbtr.business.material.entity.MaterialInfo;
import com.sbtr.business.material.service.impl.MaterialInfoServiceImpl;
import com.sbtr.business.project.service.IProjectService;
import com.sbtr.business.publishtask.service.IPublishTaskDataService;
import com.sbtr.business.trainingmodel.service.ITrainingModelDataService;
import com.sbtr.business.trainingserver.service.impl.TrainingServerServiceImpl;
import com.sbtr.business.trainingtask.entity.TrainingInfo;
import com.sbtr.business.trainingtask.service.impl.TrainingInfoServiceImpl;
import com.sbtr.common.PageDto;
import com.sbtr.common.Response;
import com.sbtr.open.project.dto.ProjectDto;
import com.sbtr.open.publishtask.dto.PublishTaskDataDto;
import com.sbtr.open.trainingmodel.dto.TrainingModelDataDto;
import com.sbtr.open.trainingmodel.dto.TrainingModelDataSearchDto;
import com.sbtr.util.FileHelper;
import com.sbtr.util.WordUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * 训练模型表 前端控制器
 * </p>
 *
 * @author yuyh2
 */
@RestController
@RequestMapping("/training-model-data")
@Api(tags = "训练模型表管理（包含模型发布、模型下载等）")
public class TrainingModelDataController {

    @Autowired
    private ITrainingModelDataService trainingModelDataService;
    @Autowired
    IPublishTaskDataService iPublishTaskDataService;
    @Autowired
    IProjectService iProjectService;
    @Autowired
    MaterialInfoServiceImpl materialInfoService;
    @Autowired
    TrainingInfoServiceImpl trainingInfoService;
    @Autowired
    AlgoCorpgenerateService algoCorpgenerateService;

    @Value("${oss.config.samplePath}")
    private String samplePath;
    /**
     * 模型存放路径
     */
    @Value("${training-task.model-base-dir}")
    private String modelBaseDir;

    @ApiOperation(value = "新的分页查询", notes = "新的分页查询", httpMethod = "POST")
    @PostMapping(value = "search-page")
    public Response<PageDto<TrainingModelDataDto>> search(@RequestBody TrainingModelDataSearchDto dto) {
        return Response.success(trainingModelDataService.search(dto));
    }

//	@ApiOperation(value = "根据id查看详情", notes = "根据id查看详情", httpMethod = "GET")
//	@RequestMapping(value = "/{id}/view-detail", method = RequestMethod.GET)
//	public Response<DetailDto> viewById(@PathVariable("id") Long id) {
//		return Response.success(trainingModelDataService.viewById(id));
//	}

    @ApiOperation(value = "根据id查找", notes = "根据id查找", httpMethod = "GET")
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public Response<TrainingModelDataDto> findById(@PathVariable("id") Long id) {
        return Response.success(trainingModelDataService.findById(id));
    }

    @ApiOperation(value = "根据id删除", notes = "根据id删除", httpMethod = "DELETE")
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public Response<Boolean> deleteById(@PathVariable("id") Long id) {
        boolean b = trainingModelDataService.deleteById(id);
        if (b) {
            return Response.success("删除成功", b);
        } else {
            return Response.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "删除失败");
        }
    }

    @ApiOperation(value = "分页查询", notes = "分页查询", httpMethod = "GET")
    @RequestMapping(value = "search", method = RequestMethod.GET)
    public Response<PageDto<TrainingModelDataDto>> search(
            @RequestParam(name = "modelName", required = false) String modelName, @RequestParam("page") Long currPage,
            @RequestParam("pageSize") Long pageSize,
            @RequestParam(name = "projectId", required = false) Long projectId) {
        return Response.success(trainingModelDataService.search(modelName, currPage, pageSize, projectId));
    }

    @ApiOperation(value = "发布模型接口", notes = "发布模型接口", httpMethod = "POST")
    @RequestMapping(value = "/{id}/publish", method = RequestMethod.POST)
    public Response<Boolean> publish(@PathVariable("id") Long id) {
        return Response.success(trainingModelDataService.publish(id));
    }

    @ApiOperation(value = "下载数据类模型文件", notes = "下载数据类模型文件", httpMethod = "GET")
    @RequestMapping(value = "/model-data-sdk/{id}", method = RequestMethod.GET)
    public void modelDataSDK(@PathVariable("id") Long id,
                             HttpServletResponse resp
    ) throws IOException {
        String tmpPath = modelBaseDir + File.separator + "tmp" + File.separator + id;
        File tmp = new File(tmpPath);
        InputStream in = null;
        if (!tmp.exists()) {
            tmp.mkdirs();
        }
//		String ossUrl = trainingModelDataService.modelDataSDK(id);
        OutputStream out = null;
        try {
            String modelDir = trainingModelDataService.modelDataSDK(id);
            if (modelDir != null) {
                File file = new File(modelDir);
                String modelName = modelDir.substring(modelDir.lastIndexOf("/") + 1, modelDir.length());
                in = new FileInputStream(file);
//		resp.setContentType("Content-Disposition;charset=UTF-8");
                resp.setContentType("application/octet-stream");
                resp.setHeader("Content-Disposition", "attachment;" + " filename=" + modelName);
                // 把本地文件发送给客户端
                out = resp.getOutputStream();
                int byteRead = 0;
                byte[] buffer = new byte[512];
                while ((byteRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, byteRead);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
                out.flush();
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

//		return Response.success(model);
    }


    @ApiOperation(value = "下载数据类模型文件,批量", notes = "下载数据类模型文件", httpMethod = "GET")
    @RequestMapping(value = "/model-data-sdk-list/{id}", method = RequestMethod.GET)
//    @RequestMapping(value = "/model-data-sdk/{id}", method = RequestMethod.GET)
    public void modelDataSDK2(@PathVariable("id") Long id, HttpServletRequest req,
                              HttpServletResponse resp
    ) throws UnsupportedEncodingException {

//        PublishTaskDataDto publishTaskDataDto = iPublishTaskDataService.findByModel(id);
//        JSONArray array = iPublishTaskDataService.getPredictJSON(publishTaskDataDto.getId());


        String tmpPath = modelBaseDir + File.separator + "tmp" + File.separator + id;
        File tmp = new File(tmpPath);
        if (!tmp.exists()) {
            tmp.mkdirs();
        }
//		String ossUrl = trainingModelDataService.modelDataSDK(id);
        String modelDir = trainingModelDataService.modelDataSDK(id);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        TrainingModelDataDto trainingModelDataDto = trainingModelDataService.findById(id);


        ProjectDto project = iProjectService.findById(trainingModelDataDto.getProjectId());

        MaterialInfo materialInfo = materialInfoService.getById(project.getFileId());

        TrainingInfo trainingInfo = trainingInfoService.getById(trainingModelDataDto.getTaskId());

        QueryWrapper<AlgoCorpgenerate> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("project_id", project.getId());
        List<AlgoCorpgenerate> algoCorpgenerate = algoCorpgenerateService.list(queryWrapper);


        TrainingModelDataDto trainingModelDataDto1 = trainingModelDataService.findByProjectId(project.getId());

        String modelFileName = trainingModelDataDto1.getModelDir().substring(trainingModelDataDto1.getModelDir().lastIndexOf("/") + 1);

        JSONObject evaluate = JSONUtil.parseObj(trainingModelDataDto1.getEvaluate());
        Set<String> types = new HashSet<>();
        types.add("1001");
        types.add("1006");
        types.add("1007");
        String typeName = "故障预测";
        if (types.contains(trainingModelDataDto.getType())) {
            typeName = "故障诊断";
        }

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("modelName", trainingModelDataDto.getModelName());
        dataMap.put("modelFileName", modelFileName);
        dataMap.put("arithmetic", trainingModelDataDto.getArithmetic());
        dataMap.put("typeName", typeName);
        dataMap.put("creater", trainingModelDataDto.getCreater());
        dataMap.put("createTime", sdf.format(trainingModelDataDto.getCreateTime()));
//        dataMap.put("params", JSONUtil.toJsonStr(array));
        dataMap.put("modelType", trainingModelDataDto.getType());
        dataMap.put("projectDesc", project.getProjectDesc());
        dataMap.put("fileName", materialInfo.getFileName());
        dataMap.put("targetColumn", trainingInfo.getTargetColumn());
        dataMap.put("variableName", trainingInfo.getVariableName());
        dataMap.put("api", trainingModelDataDto1.getApi());
        dataMap.put("type", trainingModelDataDto.getType());
        dataMap.put("algoCorpgenerate", algoCorpgenerate);


        if (typeName.equals("故障诊断")) {
            JSONObject train = JSONUtil.parseObj(evaluate.get("train"));
            dataMap.put("train_accuracy", train.get("accuracy"));
            dataMap.put("train_fl_score", train.get("fl_score"));
            dataMap.put("train_recall", train.get("recall"));

            JSONObject test = JSONUtil.parseObj(evaluate.get("test"));
            dataMap.put("test_accuracy", test.get("accuracy"));
            dataMap.put("test_fl_score", test.get("fl_score"));
            dataMap.put("test_recall", test.get("recall"));
        } else {
            JSONObject train = JSONUtil.parseObj(evaluate.get("train"));
            dataMap.put("train_rmse", train.get("rmse"));
            dataMap.put("train_r2_score", train.get("r2_score"));
            dataMap.put("train_mape", train.get("mape"));
            dataMap.put("train_mae", train.get("mae"));

            JSONObject test = JSONUtil.parseObj(evaluate.get("test"));
            dataMap.put("test_rmse", test.get("rmse"));
            dataMap.put("test_r2_score", test.get("r2_score"));
            dataMap.put("test_mape", test.get("mape"));
            dataMap.put("test_mae", test.get("mae"));

        }


        String infoDoc = typeName + "算法生成系统模型调用接口说明.doc";

        //生成word
        WordUtils.generateWord(dataMap, "基于模型诊断预测模型生成说明文档.ftl", infoDoc);
//        String path2 = this.getClass().getResource(WordUtils.basePackagePath + "/2.txt").getPath();
        String modelName = URLEncoder.encode(trainingModelDataDto.getModelName() + "_调用接口说明", "utf-8") + ".zip";
        File zipFile = new File(modelName);
        List<File> fileList = new ArrayList<>();
        fileList.add(new File(modelDir));
        fileList.add(new File(samplePath + "/generate/智能模型离线调用案例.zip"));
        fileList.add(new File(samplePath + "/generate/依赖包_requirements.txt"));
        fileList.add(new File(infoDoc));

        //压缩多文件
        ZipUtil.zip(zipFile, false, fileList.toArray(new File[0]));

        FileHelper.zipFileList(modelName, fileList, resp);
        //删除生成
        File tempFile = new File(infoDoc);
        tempFile.delete();
    }


    public void copy(InputStream inputStream, OutputStream outputStream) throws IOException {
        byte[] b = new byte[1024 * 8];
        int l;
        while ((l = inputStream.read(b)) != -1) {
            outputStream.write(b, 0, l);
            outputStream.flush();
        }
    }

    // =================新版本新增接口=====================//

    // 根据训练任务id查询模型
    @ApiOperation(value = "根据训练任务id查找模型", notes = "根据训练任务id查找模型", httpMethod = "GET")
    @RequestMapping(value = "/find-by-training-task/{taskId}", method = RequestMethod.GET)
    public Response<TrainingModelDataDto> findByTrainingTask(@PathVariable("taskId") Long taskId) {
        TrainingModelDataDto trainingModelDataDto = trainingModelDataService.findByTrainingTask(taskId);
        if (trainingModelDataDto == null) {
            return Response.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "获取预估结果失败");
        }
        return Response.success(trainingModelDataDto);
    }

    // 查询项目当前上线的模型
    @ApiOperation(value = "根据项目id查找当前上线的模型", notes = "根据项目id查找当前上线的模型", httpMethod = "GET")
    @RequestMapping(value = "/find-publish-by-project/{projectId}", method = RequestMethod.GET)
    public Response<TrainingModelDataDto> findPublishByProject(@PathVariable("projectId") Long projectId) {
        return Response.success(trainingModelDataService.findPublishByProject(projectId));
    }


    // 查询项目当前上线的模型
    @ApiOperation(value = "根据项目id查找模型", notes = "根据项目id查找模型", httpMethod = "GET")
    @RequestMapping(value = "/find-by-projectId/{projectId}", method = RequestMethod.GET)
    public Response<TrainingModelDataDto> findByProjectId(@PathVariable("projectId") Long projectId) {
        return Response.success(trainingModelDataService.findByProjectId(projectId));
    }


//	@ApiOperation(value = "根据项目Id查看历史模型", notes = "根据项目Id查看历史模型", httpMethod = "GET")
//	@RequestMapping(value = "/get-history-model-by-project/{projectId}", method = RequestMethod.GET)
//	public Response<List<HistoryModelDto>> findHistoryModelByProjectId(@PathVariable("projectId") Long projectId,
//																	   @RequestParam("page") Long currPage, @RequestParam("pageSize") Long pageSize) {
//		return Response.success(trainingModelDataService.findHistoryModelByProjectId(projectId, currPage, pageSize));
//	}

//	@ApiOperation(value = "根据模型Id获取训练数据下载链接", notes = "根据模型Id获取训练数据下载链接")
//	@RequestMapping(value = "/get-training-data-url/{modelId}", method = RequestMethod.GET)
//	public Response<TrainingDataResp> getTrainDataUrl(@PathVariable("modelId") Long modelId) {
//		return Response.success(trainingModelDataService.getTrainDataUrl(modelId));
//	}

}
